package org.bookie.framework.components;

import static org.bookie.core.services.impl.Listener.Event.BET_REMOVED;
import static org.bookie.core.services.impl.Listener.Event.BET_SLIP_PLACED;

import java.util.ArrayList;
import java.util.List;

import org.apache.hivemind.ApplicationRuntimeException;
import org.apache.tapestry.annotations.InjectObject;
import org.apache.tapestry.annotations.Persist;
import org.apache.tapestry.event.PageBeginRenderListener;
import org.apache.tapestry.event.PageEvent;
import org.bookie.core.services.impl.Listener;
import org.bookie.framework.CommonBaseComponent;
import org.bookie.model.Bet;
import org.bookie.model.Category;
import org.bookie.model.Event;
import org.bookie.model.Outcome;
import org.bookie.model.Wager;
import org.bookie.model.services.CategoryDAO;
import org.bookie.model.services.EventDAO;
import org.bookie.model.services.OutcomeDAO;

/**
 * BetList component shows a list of components to the user
 * 
 * @author zubairov
 */
public abstract class BetListComponent extends CommonBaseComponent implements
		IMenuListener, PageBeginRenderListener {

	/**
	 * Adds an entry to the betslip
	 * 
	 * @param id id of the Outcome to add
	 */
	public void addEntry(Long id) {
		Outcome outcome = getOutcomeDAO().findById(id);
		getBetSlip().addOutcome(outcome);
		updateComponents(getClientId());
	}

	/**
	 * Updates itself in case user removed a {@link Wager} from the
	 * {@link BetSlipComponent}
	 */
	@Listener( { BET_REMOVED, BET_SLIP_PLACED })
	public void betRemoved() {
		updateComponents(getClientId());
	}

	/**
	 * Removes entry from the {@link BetListComponent} view
	 * 
	 * @param id
	 *            Category ID
	 */
	public void categoryDeselected(Long id) {
		getSelectedCategoriesIds().remove(id);
		updateComponents(getClientId());
	}

	/**
	 * @see IMenuListener#categorySelected(Category)
	 */
	public void categorySelected(Category category) {
		Long id = category.getId();
		List<Long> selected = getSelectedCategoriesIds();
		if (selected.contains(id)) {
			selected.remove(id);
		}
		selected.add(0, id);
		updateComponents(getClientId());
	}

	/**
	 * Events in the current category
	 * 
	 * @return
	 */
	public List<Bet> getBets() {
		List<Event> events = getEventDAO()
				.findByCategory(getCategory().getId());
		List<Bet> result = new ArrayList<Bet>();
		for (Event event : events) {
			Bet bet = event.getMainBet();
			if (bet != null) {
				result.add(bet);
			} else {
				log.error("Event " + event.getLabel() + " (" + event.getId()
						+ " is activated but has no main bet!");
			}
		}
		return result;
	}

	/**
	 * Parameter getter for the bet slip component
	 * 
	 * @return
	 */
	public abstract IBetSlipComponent getBetSlip();

	/**
	 * Selected categories
	 * 
	 * @return
	 */
	public List<Category> getCategories() {
		return getCategoryDAO().getCategories(getSelectedCategoriesIds());
	}

	/**
	 * Temproary property used in the for cycle
	 * 
	 * @return
	 */
	public abstract Category getCategory();

	/**
	 * Injected service
	 * 
	 * @return
	 */
	@InjectObject("service:bookie.model.CategoryDAO")
	public abstract CategoryDAO getCategoryDAO();

	/**
	 * Injected service
	 * 
	 * @return
	 */
	@InjectObject("service:bookie.model.EventDAO")
	public abstract EventDAO getEventDAO();

	/**
	 * Injected service
	 * 
	 * @return
	 */
	@InjectObject("service:bookie.model.OutcomeDAO")
	public abstract OutcomeDAO getOutcomeDAO();

	/**
	 * Session persistent property
	 * 
	 * @return
	 */
	@Persist
	public abstract List<Long> getSelectedCategoriesIds();

	/**
	 * Returns true in case currently iterated event object is already selected
	 * by the user
	 * 
	 * @return
	 */
	public boolean isSelected(Outcome outcome) {
		if (outcome == null) {
			throw new ApplicationRuntimeException(getMessages().getMessage(
					"error.betSlip.null"));
		}
		boolean selected = getBetSlip().isSelected(outcome);
		return selected;
	}

	/**
	 * Initializes sesion persistent property
	 */
	public void pageBeginRender(PageEvent event) {
		if (getSelectedCategoriesIds() == null) {
			setSelectedCategoriesIds(new ArrayList<Long>());
		}
	}

	public abstract void setSelectedCategoriesIds(List<Long> list);

}
